use crate::error::{DownloadResult};
use tokio::time::{sleep, Duration};

/// 重试策略枚举
#[derive(Debug, Clone)]
pub enum RetryStrategy {
    ExponentialBackoff { max_attempts: usize, base_delay_ms: u64 },
    LinearBackoff { max_attempts: usize, delay_ms: u64 },
    NoRetry,
}

impl RetryStrategy {
    /// 获取最大重试次数
    pub fn max_retries(&self) -> usize {
        match self {
            RetryStrategy::ExponentialBackoff { max_attempts, .. } => max_attempts.saturating_sub(1),
            RetryStrategy::LinearBackoff { max_attempts, .. } => max_attempts.saturating_sub(1),
            RetryStrategy::NoRetry => 0,
        }
    }
    
    /// 获取指定重试次数的延迟时间
    pub fn retry_delay(&self, retry_attempt: usize) -> Option<Duration> {
        match self {
            RetryStrategy::ExponentialBackoff { base_delay_ms, .. } => {
                Some(Duration::from_millis(
                    base_delay_ms * (2u64.pow(retry_attempt as u32))
                ))
            }
            RetryStrategy::LinearBackoff { delay_ms, .. } => {
                Some(Duration::from_millis(*delay_ms))
            }
            RetryStrategy::NoRetry => None,
        }
    }
    
    /// 执行重试逻辑
    pub async fn execute<F, Fut, T>(&self, operation: F) -> DownloadResult<T>
    where
        F: Fn() -> Fut,
        Fut: std::future::Future<Output = DownloadResult<T>>,
        T: Send,
    {
        match self {
            RetryStrategy::ExponentialBackoff { max_attempts, base_delay_ms } => {
                self.execute_exponential_backoff(*max_attempts, *base_delay_ms, operation).await
            }
            RetryStrategy::LinearBackoff { max_attempts, delay_ms } => {
                self.execute_linear_backoff(*max_attempts, *delay_ms, operation).await
            }
            RetryStrategy::NoRetry => operation().await,
        }
    }
    
    async fn execute_exponential_backoff<F, Fut, T>(
        &self,
        max_attempts: usize,
        base_delay_ms: u64,
        operation: F,
    ) -> DownloadResult<T>
    where
        F: Fn() -> Fut,
        Fut: std::future::Future<Output = DownloadResult<T>>,
        T: Send,
    {
        let max_attempts = max_attempts.max(1);
        let mut last_error = None;
        
        for attempt in 0..max_attempts {
            match operation().await {
                Ok(result) => return Ok(result),
                Err(e) => {
                    last_error = Some(e);
                    
                    if attempt < max_attempts - 1 {
                        let delay = Duration::from_millis(
                            base_delay_ms * (2u64.pow(attempt as u32))
                        );
                        sleep(delay).await;
                    }
                }
            }
        }
        
        Err(last_error.unwrap())
    }
    
    async fn execute_linear_backoff<F, Fut, T>(
        &self,
        max_attempts: usize,
        delay_ms: u64,
        operation: F,
    ) -> DownloadResult<T>
    where
        F: Fn() -> Fut,
        Fut: std::future::Future<Output = DownloadResult<T>>,
        T: Send,
    {
        let max_attempts = max_attempts.max(1);
        let mut last_error = None;
        
        for attempt in 0..max_attempts {
            match operation().await {
                Ok(result) => return Ok(result),
                Err(e) => {
                    last_error = Some(e);
                    
                    if attempt < max_attempts - 1 {
                        sleep(Duration::from_millis(delay_ms)).await;
                    }
                }
            }
        }
        
        Err(last_error.unwrap())
    }
}

/// 重试策略工厂
pub struct RetryStrategyFactory;

impl RetryStrategyFactory {
    pub fn exponential_backoff(max_attempts: usize, base_delay_ms: u64) -> RetryStrategy {
        RetryStrategy::ExponentialBackoff {
            max_attempts,
            base_delay_ms,
        }
    }
    
    pub fn linear_backoff(max_attempts: usize, delay_ms: u64) -> RetryStrategy {
        RetryStrategy::LinearBackoff {
            max_attempts,
            delay_ms,
        }
    }
    
    pub fn no_retry() -> RetryStrategy {
        RetryStrategy::NoRetry
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::error::DownloadError;
    use std::sync::{Arc, Mutex};
    use tokio::time::{Duration, Instant};

    #[tokio::test]
    async fn test_exponential_backoff_success_first_try() {
        let strategy = RetryStrategyFactory::exponential_backoff(3, 100);
        let counter = Arc::new(Mutex::new(0));
        let counter_clone = Arc::clone(&counter);
        
        let result = strategy.execute(|| async {
            let mut count = counter_clone.lock().unwrap();
            *count += 1;
            Ok::<i32, DownloadError>(42)
        }).await;
        
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), 42);
        assert_eq!(*counter.lock().unwrap(), 1); // 只执行了一次
    }

    #[tokio::test]
    async fn test_exponential_backoff_success_after_retries() {
        let strategy = RetryStrategyFactory::exponential_backoff(3, 10); // 短的延迟时间
        let counter = Arc::new(Mutex::new(0));
        let counter_clone = Arc::clone(&counter);
        
        let result = strategy.execute(|| async {
            let mut count = counter_clone.lock().unwrap();
            *count += 1;
            
            if *count < 3 {
                Err(DownloadError::Network("网络错误".to_string()))
            } else {
                Ok::<i32, DownloadError>(42)
            }
        }).await;
        
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), 42);
        assert_eq!(*counter.lock().unwrap(), 3); // 执行了3次
    }

    #[tokio::test]
    async fn test_exponential_backoff_all_failures() {
        let strategy = RetryStrategyFactory::exponential_backoff(3, 1); // 非常短的延迟
        let counter = Arc::new(Mutex::new(0));
        let counter_clone = Arc::clone(&counter);
        
        let result = strategy.execute(|| async {
            let mut count = counter_clone.lock().unwrap();
            *count += 1;
            Err::<i32, DownloadError>(DownloadError::Network("始终失败".to_string()))
        }).await;
        
        assert!(result.is_err());
        assert_eq!(*counter.lock().unwrap(), 3); // 执行了3次
        assert!(matches!(result.unwrap_err(), DownloadError::Network(_)));
    }

    #[tokio::test]
    async fn test_exponential_backoff_timing() {
        let strategy = RetryStrategyFactory::exponential_backoff(3, 50);
        let counter = Arc::new(Mutex::new(0));
        let counter_clone = Arc::clone(&counter);
        
        let start_time = Instant::now();
        
        let _result = strategy.execute(|| async {
            let mut count = counter_clone.lock().unwrap();
            *count += 1;
            Err::<i32, DownloadError>(DownloadError::Network("测试错误".to_string()))
        }).await;
        
        let elapsed = start_time.elapsed();
        
        // 验证总的等待时间大致符合指数退避策略
        // 50ms + 100ms = 150ms 的等待时间，加上执行时间
        assert!(elapsed >= Duration::from_millis(140)); // 允许一些误差
        assert!(elapsed < Duration::from_millis(500)); // 不应该太长
    }

    #[tokio::test]
    async fn test_linear_backoff_success() {
        let strategy = RetryStrategyFactory::linear_backoff(3, 10);
        let counter = Arc::new(Mutex::new(0));
        let counter_clone = Arc::clone(&counter);
        
        let result = strategy.execute(|| async {
            let mut count = counter_clone.lock().unwrap();
            *count += 1;
            
            if *count < 2 {
                Err(DownloadError::Io("文件错误".to_string()))
            } else {
                Ok::<String, DownloadError>("success".to_string())
            }
        }).await;
        
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), "success");
        assert_eq!(*counter.lock().unwrap(), 2);
    }

    #[tokio::test]
    async fn test_linear_backoff_timing() {
        let strategy = RetryStrategyFactory::linear_backoff(3, 30);
        let counter = Arc::new(Mutex::new(0));
        let counter_clone = Arc::clone(&counter);
        
        let start_time = Instant::now();
        
        let _result = strategy.execute(|| async {
            let mut count = counter_clone.lock().unwrap();
            *count += 1;
            Err::<i32, DownloadError>(DownloadError::Url("测试错误".to_string()))
        }).await;
        
        let elapsed = start_time.elapsed();
        
        // 线性退避：30ms + 30ms = 60ms
        assert!(elapsed >= Duration::from_millis(50));
        assert!(elapsed < Duration::from_millis(200));
    }

    #[tokio::test]
    async fn test_no_retry_success() {
        let strategy = RetryStrategyFactory::no_retry();
        let counter = Arc::new(Mutex::new(0));
        let counter_clone = Arc::clone(&counter);
        
        let result = strategy.execute(|| async {
            let mut count = counter_clone.lock().unwrap();
            *count += 1;
            Ok::<&str, DownloadError>("immediate success")
        }).await;
        
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), "immediate success");
        assert_eq!(*counter.lock().unwrap(), 1);
    }

    #[tokio::test]
    async fn test_no_retry_failure() {
        let strategy = RetryStrategyFactory::no_retry();
        let counter = Arc::new(Mutex::new(0));
        let counter_clone = Arc::clone(&counter);
        
        let result = strategy.execute(|| async {
            let mut count = counter_clone.lock().unwrap();
            *count += 1;
            Err::<i32, DownloadError>(DownloadError::InvalidM3u8)
        }).await;
        
        assert!(result.is_err());
        assert_eq!(*counter.lock().unwrap(), 1); // 只执行一次，不重试
        assert!(matches!(result.unwrap_err(), DownloadError::InvalidM3u8));
    }

    #[tokio::test]
    async fn test_retry_strategy_clone() {
        let strategy1 = RetryStrategyFactory::exponential_backoff(5, 100);
        let strategy2 = strategy1.clone();
        
        // 测试克隆的策略具有相同的行为
        let counter1 = Arc::new(Mutex::new(0));
        let counter2 = Arc::new(Mutex::new(0));
        
        let counter1_clone = Arc::clone(&counter1);
        let counter2_clone = Arc::clone(&counter2);
        
        let result1 = strategy1.execute(|| async {
            *counter1_clone.lock().unwrap() += 1;
            Ok::<i32, DownloadError>(1)
        }).await;
        
        let result2 = strategy2.execute(|| async {
            *counter2_clone.lock().unwrap() += 1;
            Ok::<i32, DownloadError>(2)
        }).await;
        
        assert!(result1.is_ok());
        assert!(result2.is_ok());
        assert_eq!(*counter1.lock().unwrap(), 1);
        assert_eq!(*counter2.lock().unwrap(), 1);
    }

    #[tokio::test]
    async fn test_retry_strategy_debug() {
        let strategies = vec![
            RetryStrategyFactory::exponential_backoff(3, 100),
            RetryStrategyFactory::linear_backoff(5, 50),
            RetryStrategyFactory::no_retry(),
        ];
        
        for strategy in strategies {
            let debug_str = format!("{strategy:?}");
            assert!(!debug_str.is_empty());
            
            // 验证Debug输出包含类型信息
            assert!(debug_str.contains("ExponentialBackoff") || 
                   debug_str.contains("LinearBackoff") || 
                   debug_str.contains("NoRetry"));
        }
    }

    #[tokio::test]
    async fn test_retry_strategy_extreme_values() {
        // 测试极端值
        let strategy = RetryStrategyFactory::exponential_backoff(1, 1); // 最小配置
        let result = strategy.execute(|| async {
            Ok::<i32, DownloadError>(100)
        }).await;
        
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), 100);
        
        // 测试较大的重试次数（但不要太大以免测试超时）
        let strategy = RetryStrategyFactory::linear_backoff(10, 1);
        let counter = Arc::new(Mutex::new(0));
        let counter_clone = Arc::clone(&counter);
        
        let result = strategy.execute(|| async {
            let mut count = counter_clone.lock().unwrap();
            *count += 1;
            if *count < 5 {
                Err(DownloadError::Network("测试".to_string()))
            } else {
                Ok::<i32, DownloadError>(42)
            }
        }).await;
        
        assert!(result.is_ok());
        assert_eq!(*counter.lock().unwrap(), 5);
    }

    #[test]
    fn test_retry_strategy_factory() {
        // 测试工厂方法的参数验证
        let exponential = RetryStrategyFactory::exponential_backoff(3, 100);
        assert!(matches!(exponential, RetryStrategy::ExponentialBackoff { max_attempts: 3, base_delay_ms: 100 }));
        
        let linear = RetryStrategyFactory::linear_backoff(5, 50);
        assert!(matches!(linear, RetryStrategy::LinearBackoff { max_attempts: 5, delay_ms: 50 }));
        
        let no_retry = RetryStrategyFactory::no_retry();
        assert!(matches!(no_retry, RetryStrategy::NoRetry));
    }
}